package com.iob.coin.covid19kg.dataset;

import com.iob.coin.config.DatasetConfig;
import org.apache.jena.jdbc.tdb.connections.TDBConnection;
import org.apache.jena.query.*;
import org.apache.jena.rdf.model.*;
import org.apache.jena.tdb.TDBFactory;
import org.apache.jena.vocabulary.RDF;
import org.apache.jena.vocabulary.RDFS;
import org.springframework.stereotype.Component;

import java.util.LinkedList;
import java.util.List;

/**
 * @Author: GuoXinyuan
 * @Date: 2021/5/29
 * 使用本地TDB API获取
 */

@Component
public class DatasetManagerLocalImpl implements DatasetManager{

    /**
     * tdb dataset
     */
    private final Dataset dataset = TDBFactory.createDataset(DatasetConfig.COVID19_DATASET_PATH);

    public Dataset getDataset(){
        return dataset;
    }

    @Override
    public List<RDFNode> getResourceByLabel(String label) {

        String subjectName = "subject";
        String objectName = "object";

        //生成sparql语句
        String sparql = "SELECT ?" + subjectName + " " +
                "WHERE { " +
                    "{ ?" + subjectName + " <" + RDFS.label.getURI() + "> ?" + objectName + " " +
                    "filter regex(?" + objectName + ",'" + label + "') .  }" +
                "}";

        //创建查询
        Model defaultModel = dataset.getDefaultModel();
        Query query = QueryFactory.create(sparql);
        QueryExecution qexec = QueryExecutionFactory.create(query, defaultModel);
        ResultSet resultSet = qexec.execSelect();

//        List<Resource> results = new LinkedList<>();
        List<RDFNode> results = new LinkedList<>();

        //处理结果集
        while (resultSet.hasNext()){
            QuerySolution querySolution = resultSet.nextSolution();
            RDFNode resource = querySolution.get(subjectName);
//            Resource resource = querySolution.getResource(subjectName);
            results.add(resource);
        }

        if(label.equals("类型")||label.equals("种类"))
            results.add(RDF.type);

        return results;

    }

    @Override
    public Resource getResource(String uri) {
        Model defaultModel = dataset.getDefaultModel();
        return defaultModel.getResource(uri);
    }

    @Override
    public Statement getProperty(Resource resource,Property property){
        Model defaultModel = dataset.getDefaultModel();
        return defaultModel.getProperty(resource,property);
    }

    @Override
    public List<Statement> listStatements(Resource resource,Property property,RDFNode rdfNode){
        Model defaultModel = dataset.getDefaultModel();
        return defaultModel.listStatements(resource,property,rdfNode).toList();
    }

    @Override
    public List<Statement> searchAboutResource(Resource resource) {
        Model defaultModel = dataset.getDefaultModel();
        List<Statement> result = defaultModel.listStatements(resource,null,(RDFNode)null).toList();
        List<Statement> l2 = defaultModel.listStatements(null,null,resource).toList();
        result.addAll(l2);
        return result;
    }

    @Override
    public boolean isBaseType(Resource resource) {
        return RDF.Property.getURI().equals(resource.getURI())
                || RDFS.Resource.getURI().equals(resource.getURI())
                || RDFS.Class.getURI().equals(resource.getURI())
                || DefaultURI.xmlString.equals(resource.getURI());
    }

    @Override
    public Resource getType(Resource resource) {
        Model defaultModel = dataset.getDefaultModel();
        if(isBaseType(resource)) return null;
        return defaultModel.getProperty(resource,RDF.type).getObject().asResource();
    }

    @Override
    public Resource getRDFBaseType(Resource resource) {
        //本身就是基类型则直接返回
        if(resource.equals(RDFS.Class) || resource.equals(RDF.Property) || resource.equals(RDFS.Resource)){
            return resource;
        }

        if(resource.getURI().startsWith(DefaultURI.classPrefix)) return RDFS.Class;
        else if(resource.getURI().startsWith(DefaultURI.resourcePrefix)) return RDFS.Resource;
        else if(resource.getURI().startsWith(DefaultURI.propertyPrefix)) return RDF.Property;

        return null;
    }

    @Override
    public String getLabel(Resource resource,String lang) {
        Model defaultModel = dataset.getDefaultModel();
        Statement statement = defaultModel.getProperty(resource,RDFS.label,lang);
        if(statement==null) return null;
        return statement.getObject().asLiteral().getString();
    }

    //---------------------

    private static void printTriple(Resource subject,Property property,RDFNode object,int count){
        System.out.print(count + ":主语");
        printResource(subject);
        System.out.print(" -> ");

        System.out.print("谓语");
        printResource(property);
        System.out.print(" -> ");

        System.out.print("宾语");
        printRDFNode(object);

        System.out.println();
    }

    private static void printResource(Resource resource){
        if (resource == null) {
            System.out.print("null");
            return;
        }
        System.out.print("(URI:<");
        System.out.print(resource.getURI());
        System.out.print("> label:");
        if(resource.hasProperty(RDFS.label)) System.out.print(resource.getProperty(RDFS.label).getString());
        System.out.print(")");
    }

    private static void printRDFNode(RDFNode rdfNode){
        if (rdfNode == null) {
            System.out.print("null");
            return;
        }
        if(rdfNode.isResource()){
            printResource(rdfNode.asResource());
        }
        else if(rdfNode.isLiteral()){
            System.out.print("(literal:");
            System.out.print(rdfNode.asLiteral().getString());
            System.out.print(")");
        }
        else {
            System.out.print("(rdfNode:" + rdfNode.getClass().getSimpleName() + ")");
        }
    }
}
